package com.lagou.edu.support;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Repository;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.utils.ClassUtil;

import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName ClassPathXmlApplicationContext
 * @Description TODO
 * @Author 陶肖寅
 * @Date : 2020-01-14 09:53
 * @Version 1.0
 **/
public class ClassPathXmlApplicationContext {
    // 扫包范围
    private String packageName;
    private static ConcurrentHashMap<String, Object> beans = null;
    public ClassPathXmlApplicationContext(String packageName) throws Exception {
        this.packageName = packageName;
        beans = new ConcurrentHashMap<String, Object>();
        /**
         * @Author 陶肖寅
         * @Description 初始化beans
         * @Date 10:28 2020/1/14
         * @Param [packageName]
         * @return
         **/
        initBeans();
        // 初始化属性Autowired注解
        initAttris();
    }
    /**
     * @Author 陶肖寅
     * @Description //初始化注入
     * @Date 09:54 2020/1/14
     * @Param []
     * @return void
     **/
    private void initAttris() throws Exception {
        for (Object o : beans.keySet()) {
            System.out.println("key=" + o + " value=" + beans.get(o));
            // 依赖注入
            attriAssign(beans.get(o));
        }
    }
    /**
     * @Author 陶肖寅
     * @Description 初始化对象
     * @Date 09:59 2020/1/14
     * @Param []
     * @return void
     **/
    public void initBeans() throws IllegalArgumentException, IllegalAccessException {
        // 1.扫描包有的类，获取所有类
        List<Class<?>> classes = ClassUtil.getClasses(packageName);
        // 2.判断是否有注解
        ConcurrentHashMap<String, Object> findClassExisAnnotation = findClassExisAnnotation(classes);
        if (findClassExisAnnotation == null || findClassExisAnnotation.isEmpty()) {
            throw new RuntimeException("该包下没有这个注解");
        }
    }
    /**
     * @Author 陶肖寅
     * @Description 根据beanId获取bean
     * @Date 10:29 2020/1/14
     * @Param [beanId]
     * @return java.lang.Object
     **/
    public  Object getBean(String beanId) {
        if (beanId == null || StringUtils.isEmpty(beanId)) {
            throw new RuntimeException("beanId不能为空");
        }
        Object class1 = beans.get(beanId);
        if (class1 == null) {
            throw new RuntimeException("该包下没有BeanId为" + beanId + "的类");
        }
        return class1;
    }
    /**
     * @Author 陶肖寅
     * @Description //TODO获取注解
     * @Date 10:00 2020/1/14
     * @Param [classes]
     * @return java.util.concurrent.ConcurrentHashMap<java.lang.String,java.lang.Object>
     **/
    public ConcurrentHashMap<String, Object> findClassExisAnnotation(List<Class<?>> classes)
            throws IllegalArgumentException, IllegalAccessException {
        for (Class<?> class1 : classes) {
            Service annotation = class1.getAnnotation (Service.class);
            if (annotation != null) {
                ///获取service注解value值
                String beanId = annotation.value();
                if (StringUtils.isEmpty(beanId)) {
                    //判断是否配置了value，如果未配置，则将类名第一个字段是小写的为beanId
                    beanId = toLowerCaseFirstOne(class1.getSimpleName());
                }
                Object newInstance = newInstance(class1);
                beans.put(beanId, newInstance);
            }
            Repository repositoryAnnotation = class1.getAnnotation (Repository.class);
            if (repositoryAnnotation != null) {
                ///获取service注解value值
                String beanId = repositoryAnnotation.value();
                if (StringUtils.isEmpty(beanId)) {
                    //判断是否配置了value，如果未配置，则将类名第一个字段是小写的为beanId
                    beanId = toLowerCaseFirstOne(class1.getSimpleName());
                }
                Object newInstance = newInstance(class1);
                beans.put(beanId, newInstance);
            }
        }
        return beans;
    }

    /**
     * @Author 陶肖寅
     * @Description 首字母转小写
     * @Date 10:17 2020/1/14
     * @Param [s] 类型
     * @return java.lang.String
     **/
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0)))
        {
            return s;
        }
        else{
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }
    /**
     * @Author 陶肖寅
     * @Description //通过反射生成对象
     * @Date 10:18 2020/1/14
     * @Param [classInfo]
     * @return java.lang.Object
     **/
    public Object newInstance(Class<?> classInfo) {
        try {
            return classInfo.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("反射生成对象失败" + e.getMessage());
        }
    }

    /**
     * @Author 陶肖寅
     * @Description //依赖注入实现原理
     * @Date 10:18 2020/1/14
     * @Param [object] 注入对象
     * @return void
     **/
    public void attriAssign(Object object) throws Exception {
        // 1.使用反射机制获取当前类的所有属性
        Field[] declaredFields = object.getClass().getDeclaredFields();
        // 2.判断当前类是否存在注解
        for (Field field : declaredFields) {
            Autowired annotation = field.getAnnotation(Autowired.class);
            if (annotation != null) {
                // 获取属性名称
                String name = field.getName();
                // 根据beanName查找对象
                Object newBean = getBean(name);
                // 3.默认使用属性名称,查找bean容器对象
                if (object != null) {
                    field.setAccessible(true);
                    // 给属性赋值 将对象注入到 属性中
                    field.set(object, newBean);
                }
            }
        }
    }
}
